// -*-c#-*-
// License: New BSD License : http://www.opensource.org/licenses/bsd-license.php
//
// Copyright (c) 2008, Brothers In Arms/Burl Nyswonger
//
// See: BiaVote.uc for full License
// 
//@L

class BiaVoteStat extends Info
    Config(BiaVoteStat);

//
// This class is for tracking stats - TODO: use the stats, lol...
// It seemed prudent to isolate this information to a different
// .ini file than UTBiaVote.ini
//
// Issues:
//   Having trouble using an array of structs in a config array - won't
//   initialize with SaveConfig().  I want this to work the first time
//   without a UTBiaVoteStat.ini -- So I made this GetRec/PutRec mess
//   to get around it.  Must revisit...
//

`include( BiaVote/Classes/BiaStdInc.uci )
`include( BiaVote/Classes/BiaVote.uci   )

// ----------------------------------------------------------------------------

struct BiaVoteMapStat
{
    var string MapName;
    var int nPlayed, LastPlayed;
    structdefaultproperties
    {
        MapName=""
        nPlayed=1
        LastPlayed=1
    }
};

const MAPMARKER = "no-map-should-be-named-this";

var array<string> AscT;
var array<BiaVoteMapStat> aMapStats;
var bool bLastGameEnded;

// config stuff...
var config array<string> MapStats;
var config int GameCount, LastGameNo;
var config string LastGameName, LastMapName, ThisVersion;
var config bool LastGameEnded;

// need to see who's new and who's traveling...
// there must be a better way - but this works for now...
var config array<string> Travelers;

// ----------------------------------------------------------------------------


auto state Spawned
{
    function BeginState( Name PrevState )
    {
        InitStats();
    }
}

// ---------------------------------------------------------------------------

private function InitStats()
{
    aMapStats.Length = 1;
    aMapStats[0].MapName = "no-map-should-be-named-this";
    aMapStats[0].nPlayed = 1;
    aMapStats[0].LastPlayed =1;
    
    bLastGameEnded=LastGameEnded;
    
    if( bLastGameEnded == false )
    {
        Travelers.Length = 0;
        Travelers.AddItem("+++");
    }
    
    LastGameEnded=false;
    if( ThisVersion != `BiaVoteVersion )
    {
        ThisVersion = `BiaVoteVersion;
        MapStats.Length = 0;
    }
    else
    {
        ReadMapStats();
    }
    GameCount = max(1,GameCount);
    LastGameNo = max(1, GameCount);
    LastGameNo = GameCount;
    GameCount += 1;
    SaveConfig();
}

// just in case we got a URL or something - and remove any ':' chars.
private function FixMapName( out string Nm )
{
    local int i;
    i = Instr(Nm, "?");
    if( i > 0 )
    {
        Nm = Left(Nm, i);
    }
    Nm = Locs(nm);
    Repl(Nm, " ", "");
    Repl(Nm, ":", "");
}

private function bool PutRec(BiaVoteMapStat st, out string rec)
{
    local string mn;
    
    mn = st.MapName;
    FixMapName(mn);
    if( mn != "" )
    {
        rec =  string(max(1,st.nPlayed)) $ ":";
        rec $= string(max(1,st.LastPlayed)) $ ":";
        rec $= Locs(st.MapName);
        return true;
    }
    return false;
}
private function bool GetRec(string rec, out BiaVoteMapStat st)
{
    local array<string> aRec;

    
    aRec.Length = 0;
    ParseStringIntoArray(rec, aRec, ":", true);
    if(aRec.Length == 3)
    {
        st.nPlayed = int( aRec[0] );
        st.LastPlayed = int( aRec[1] );
        st.MapName = Locs( aRec[2] );
        if( st.nPlayed > 0 && st.LastPlayed > 0 && st.MapName != "" )
        {
            return true;
        }
    }
    return false;
}

private function WriteMapStats()
{
    local int i;
    local string rec;
    

    `BiaAssert( aMapStats.Length > 0 );
    
    MapStats.Length = 1;
    MapStats[0]="1:1:" $ MAPMARKER;

    `BiaDbg("Writing Map Stats: " $ aMapStats.Length);
    
    for(i=1; i< aMapStats.Length; i++)
    {
        if( PutRec(aMapStats[i], rec ))
        {
            `BiaDbg("Savging record: " $ rec );
            MapStats.AddItem(rec);
        }
        else
        {
            `BiaDbg("bad record for: " $ aMapStats[i].MapName);
        }
    }
}
private function bool ReadMapStats()
{
    local int i, Idx;
    local bool bDirty;
    local BiaVoteMapStat st;

    bDirty = true;
    
    if( MapStats.Length > 0 )
    {
        bDirty = false;
        `BiaDbg("there are " $ MapStats.Length $ " records");
        for(i=0; i<MapStats.Length; i++)
        {
            `BiaDbg("checking stats record: " $ MapStats[i]);
            if( GetRec( MapStats[i], st ) )
            {
                if( st.MapName ~= MAPMARKER )
                {
                    continue;
                }
                Idx = aMapStats.Find('MapName', st.MapName);
                if( Idx > -1 )
                {
                    `BiaDbg("record is a duplicate");
                    bDirty = true;
                }
                else
                {
                    `BiaDbg("record added");
                    aMapStats.AddItem( st );
                }
            }
            else
            {
                `BiaDbg("record is corrupt");
                bDirty = true;
            }
        }
    }
    else
    {
        `BiaWarn("No stats in ini file!");
    }
    return bDirty;
}

//
// I don't trust stuff!  There are a lot of funny characters that seem to
// screw things up on the game - so I'm just going to make sure that any
// string I put into the .ini file that can originate with a user will
// be sanitized -- till I know what is safe/legal..
//
private function string sanitize_str( string pn )
{
    local int i;
    local string res;
    
    pn = locs(pn);
    res = "";
    
    for(i=0; i< Len(pn); i++)
    {
        res $= AscT[ Asc(Mid(pn, i, 1)) & 0x7f ];
    }
    
    return res;
}

// clean up the playername, convert to lower case, etc. (above)
private function string CleanPlayerName( PlayerController PC )
{
    if( PC != None && PC.PlayerReplicationInfo != None )
    {
        return( sanitize_str(PC.PlayerReplicationInfo.PlayerName) );
    }
    return "";
}

function bool IsTraveling( PlayerController PC )
{
    local string pn;
    
    pn = CleanPlayerName( PC );
    if( Travelers.Find(pn) > -1 )
    {
        `BiaDbg("Player:[" $ pn $ "] is traveling ");
        return true;
    }
    `BiaDbg("Player:[" $ pn $ "] did not travel");
    return false;
}

function string GetLastGame()
{
    return LastGameName;
}

function string GetLastMap()
{
    return LastMapName;
}

function RecordStats( string oldmap, string newgame, array<PlayerController> aPC )
{
    local int idx;
    local string pn;

    FixMapName(oldmap);
    LastMapName = oldmap;
    LastGameName = newgame;
    LastGameEnded = true;
    
    `BiaDbg("There are " $ aMapStats.Length $ " records in aMapStats[]");
    
    idx = aMapStats.Find('MapName', oldmap);
    if( idx < 0 )
    {
        idx = aMapStats.Length;
        aMapStats.Add(1);
    }
    aMapStats[idx].MapName = oldmap;
    aMapStats[idx].nPlayed += 1;
    aMapStats[idx].LastPlayed = GameCount;

    Travelers.Length = 0;
    Travelers[0] = "player";
    for(idx = 0; idx < aPc.Length; idx++)
    {
        pn = CleanPlayerName( aPC[idx] );
        if(pn != "") {
            Travelers[Travelers.Length] = pn;
        }
    }
    WriteMapStats();
    SaveConfig();
}

defaultproperties
{
 
 // Stupid compiler tells me I can't do static-sized arrays :-( 
 // Must be exactly 128 entries - don't mess with it!
    AscT(  0)="_"
    AscT(  1)="_"
    AscT(  2)="_"
    AscT(  3)="_"
    AscT(  4)="_"
    AscT(  5)="_"
    AscT(  6)="_"
    AscT(  7)="_"
    AscT(  8)="_"
    AscT(  9)="_"
    AscT( 10)="_"
    AscT( 11)="_"
    AscT( 12)="_"
    AscT( 13)="_"
    AscT( 14)="_"
    AscT( 15)="_"
    AscT( 16)="_"
    AscT( 17)="_"
    AscT( 18)="_"
    AscT( 19)="_"
    AscT( 20)="_"
    AscT( 21)="_"
    AscT( 22)="_"
    AscT( 23)="_"
    AscT( 24)="_"
    AscT( 25)="_"
    AscT( 26)="_"
    AscT( 27)="_"
    AscT( 28)="_"
    AscT( 29)="_"
    AscT( 30)="_"
    AscT( 31)="_"
    AscT( 32)="_"
    AscT( 33)="_"
    AscT( 34)="_"
    AscT( 35)="_"
    AscT( 36)="_"
    AscT( 37)="_"
    AscT( 38)="_"
    AscT( 39)="_"
    AscT( 40)="_"
    AscT( 41)="_"
    AscT( 42)="_"
    AscT( 43)="_"
    AscT( 44)="_"
    AscT( 45)="_"
    AscT( 46)="_"
    AscT( 47)="_"
    AscT( 48)="0"
    AscT( 49)="1"
    AscT( 50)="2"
    AscT( 51)="3"
    AscT( 52)="4"
    AscT( 53)="5"
    AscT( 54)="6"
    AscT( 55)="7"
    AscT( 56)="8"
    AscT( 57)="9"
    AscT( 58)="_"
    AscT( 59)="_"
    AscT( 60)="_"
    AscT( 61)="_"
    AscT( 62)="_"
    AscT( 63)="_"
    AscT( 64)="_"
    AscT( 65)="a"
    AscT( 66)="b"
    AscT( 67)="c"
    AscT( 68)="d"
    AscT( 69)="e"
    AscT( 70)="f"
    AscT( 71)="g"
    AscT( 72)="h"
    AscT( 73)="i"
    AscT( 74)="j"
    AscT( 75)="k"
    AscT( 76)="l"
    AscT( 77)="m"
    AscT( 78)="n"
    AscT( 79)="o"
    AscT( 80)="p"
    AscT( 81)="q"
    AscT( 82)="r"
    AscT( 83)="s"
    AscT( 84)="t"
    AscT( 85)="u"
    AscT( 86)="v"
    AscT( 87)="w"
    AscT( 88)="x"
    AscT( 89)="y"
    AscT( 90)="z"
    AscT( 91)="_"
    AscT( 92)="_"
    AscT( 93)="_"
    AscT( 94)="_"
    AscT( 95)="_"
    AscT( 96)="_"
    AscT( 97)="a"
    AscT( 98)="b"
    AscT( 99)="c"
    AscT(100)="d"
    AscT(101)="e"
    AscT(102)="f"
    AscT(103)="g"
    AscT(104)="h"
    AscT(105)="i"
    AscT(106)="j"
    AscT(107)="k"
    AscT(108)="l"
    AscT(109)="m"
    AscT(110)="n"
    AscT(111)="o"
    AscT(112)="p"
    AscT(113)="q"
    AscT(114)="r"
    AscT(115)="s"
    AscT(116)="t"
    AscT(117)="u"
    AscT(118)="v"
    AscT(119)="w"
    AscT(120)="x"
    AscT(121)="y"
    AscT(122)="z"
    AscT(123)="_"
    AscT(124)="_"
    AscT(125)="_"
    AscT(126)="_"
    AscT(127)="_"

}

